using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace SymAutomate
{
    /// <summary>
    /// Base class for all Drivers
    /// Error Numbers 150-169; Reference file ErrorNumbers.txt for more information.
    /// 151 Error: HostTelnetConnectionDriver for %class name% is null. Call the correct constructor before calling ProcessCommand().
    /// 150 Error: %class name% does not respond to specified command '%command name%' or no mapping defined in %class name%.PopulateCommandToFunctionMapping().
    /// 152 Error: CommandToFunctionMapping collection is null. Implement default constructor for %class name% with :base() to resolve the issue.
    /// 153 Error: %function name%() function not found in %class name%.
    /// 154 Error: Invoking method '%function name%' failed for %class name%. %exception message%.
    /// </summary>
    class DriverBase
    {
        private List<ConsoleHelp> __ConsoleHelpList;
        private Dictionary<string, string> __CommandToFunctionMapping;
        private HostTelnetConnection.Driver __HostTelnetConnectionDriver;

        public List<ConsoleHelp> ConsoleHelpList { get { return __ConsoleHelpList; } }
        public Dictionary<string, string> CommandToFunctionMapping { get { return __CommandToFunctionMapping; } set { __CommandToFunctionMapping = value; } }
        public HostTelnetConnection.Driver HostTelnetConnectionDriver { get { return __HostTelnetConnectionDriver; } set { __HostTelnetConnectionDriver = value; } }

        public DriverBase()
        {
            __CommandToFunctionMapping = new Dictionary<string, string>();
            this.CallSuperPopulateCommandToFunctionMapping();
            __ConsoleHelpList = new List<ConsoleHelp>();
            this.CallSuperPopulateConsoleHelp();
        }

        public DriverBase(HostTelnetConnection.Driver _HostTelnetConnectionDriver)
        {
            __CommandToFunctionMapping = new Dictionary<string, string>();
            __HostTelnetConnectionDriver = _HostTelnetConnectionDriver;
            this.CallSuperPopulateCommandToFunctionMapping();
            __ConsoleHelpList = new List<ConsoleHelp>();
            this.CallSuperPopulateConsoleHelp();
        }

        /// <summary>
        /// Calls the super class PopulateCommandToFunctionMapping function
        /// </summary>
        private void CallSuperPopulateCommandToFunctionMapping()
        {
            MethodInfo _MethodInfo = null;
            _MethodInfo = this.GetType().GetMethod("PopulateCommandToFunctionMapping");
            _MethodInfo.Invoke(this, null);
        }

        /// <summary>
        /// Calls the super class PopulateConsoleHelp function
        /// </summary>
        private void CallSuperPopulateConsoleHelp()
        {
            MethodInfo _MethodInfo = null;
            _MethodInfo = this.GetType().GetMethod("PopulateConsoleHelp");
            _MethodInfo.Invoke(this, null);
        }

        /// <summary>
        /// Returns true if this driver responds to HostTelnetConnectionDriver.Parameters.Command (command specified in command line)
        /// </summary>
        /// <returns></returns>
        public bool RespondsToCommand(string _Command)
        {
            if (__CommandToFunctionMapping == null)
                throw new ReturnException("152 Error: CommandToFunctionMapping collection is null. Implement default constructor for " + this.GetType().ToString() + " with :base() to resolve the issue.");
            if (__CommandToFunctionMapping.ContainsKey(_Command.ToLower())) return true;
            return false;
        }

        /// <summary>
        /// Process the command on this inherited driver
        /// </summary>
        public void ProcessCommand()
        {
            if (__HostTelnetConnectionDriver == null)
            {
                throw new ReturnException("151 Error: HostTelnetConnectionDriver for " + this.GetType().ToString() + " is null. Call the correct constructor before calling ProcessCommand().");
            }

            if (this.RespondsToCommand(__HostTelnetConnectionDriver.Parameters.Command))
            {
                MethodInfo _MethodInfo = null;
                _MethodInfo = this.GetType().GetMethod(__CommandToFunctionMapping[__HostTelnetConnectionDriver.Parameters.Command.ToLower()]);
                if (_MethodInfo == null)
                    throw new ReturnException("153 Error: " + __CommandToFunctionMapping[__HostTelnetConnectionDriver.Parameters.Command.ToLower()] + "() function not found in " + this.GetType().ToString() + ".");
                try
                {
                    _MethodInfo.Invoke(this, null);
                }
                catch (System.Reflection.TargetParameterCountException _MethodInvokeException)
                {
                    throw new ReturnException("154 Error: Invoking method '" + __CommandToFunctionMapping[__HostTelnetConnectionDriver.Parameters.Command.ToLower()] + "' failed for " + this.GetType().ToString() + ". " + _MethodInvokeException.Message);
                }
                catch (System.Reflection.TargetInvocationException _TargetInvocationException)
                {
                    FieldInfo _RemoteStackTraceString = typeof(Exception).GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic);
                    _RemoteStackTraceString.SetValue(_TargetInvocationException.InnerException, _TargetInvocationException.InnerException.StackTrace + Environment.NewLine);
                    throw _TargetInvocationException.InnerException;
                }
            }
            else
            {
                throw new ReturnException("150 Error: " + this.GetType().ToString() + " does not respond to specified command '" + __HostTelnetConnectionDriver.Parameters.Command + "' or no mapping defined in " + this.GetType().ToString() + ".PopulateCommandToFunctionMapping().");
            }
        }
    }
}
